package de.koller.gravity.scene.map;

import de.koller.aframe.util.misc.BufferedRandomFloat;
import de.koller.aframe.util.misc.ColorGradient;
import de.koller.aframe.util.misc.ColorOperations;
import de.koller.aframe.util.noise.n2D.CPerlin2D;
import de.koller.aframe.util.noise.n2D.Noise2D;
import de.koller.aframe.util.noise.n2D.Perlin2D;
import de.koller.aframe.util.resource.IOLoader;
import de.koller.gravity.scene.Scene;
import de.koller.oceanFramework.math.RVec3;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;

public class MapScene extends Scene {

	public Random rnd = new Random();
	private BufferedRandomFloat bfr = new BufferedRandomFloat( "./screenshots/ch/bigMap", rnd );
	
	public float k = .25f;
	public float waterheight = .5f * k;
	public float beachheight = .6f * k;
	public float snowheight = .75f * k;
	
	public int startStep = 0;
	public int steps = 8;
	public final int size = 700;
	
	public float persistence = .65f;
	
	public boolean topology = false;
	
	private final RVec3 lightVector = new RVec3( 1f, .2f, .8f );
	private final RVec3 eyevector = new RVec3( 0, 0, 1f );
	
	public static void main( String[] args ) {
//		MapSceneTester frame = new MapSceneTester();
//		frame.setVisible( true );
//		frame.genImg();
		
//		MapScene m = new MapScene();
//		for( int x = 0; x < 25; x++ )
//			for( int y = 0; y < 25; y++ ) {
//				IOLoader.savePNG( m.renderScene( x, y ), "./screenshots/subImg_" + x + "_" + y + ".png" );
//			}
		
		BufferedImage i = new BufferedImage( 500*25, 500*25, BufferedImage.TYPE_INT_RGB );
		Graphics2D g = i.createGraphics();
		int p = 0;
		for( int x = 0; x < 25; x++ )
			for( int y = 0; y < 25; y++ ) {
				BufferedImage s = IOLoader.loadLocalImage( "./screenshots/subImg_" + x + "_" + y + ".png" );
				g.drawImage( s, x*500, y*500, null );
				//IOLoader.savePNG( m.renderScene( x, y ), "./screenshots/subImg_" + x + "_" + y + ".png" );
				
				System.out.println( p++ );
			}
		
		IOLoader.savePNG( i, "./screenshots/full2.png" );
	}
	
	@Override
	public BufferedImage renderScene() {
		return renderScene( 0, 0 );
	}
	
	public BufferedImage renderScene( int x, int y ) {
		BufferedImage r = new BufferedImage( size, size, BufferedImage.TYPE_INT_RGB );
		
		CPerlin2D.PRINT_PROGRESS = true;
		CPerlin2D p = new CPerlin2D( x, y, bfr, startStep, steps, persistence );
		p.normalizeMaxBound( (1f/k) * Perlin2D.maxHeight( startStep, steps, persistence ) );
		
		//p.normalizeMaxBound( Perlin2D.maxHeight( startStep, steps, persistence ) );
		
		//Function3DPreview.showFunction( 0, 0, 1, 1, c );
		
		drawSurface( r, p );
		
		return r;
	}
	
	private void drawSurface( BufferedImage b, Noise2D p ) {
		for( int x = 0; x < b.getWidth(); x++ )
			for( int y = 0; y < b.getHeight(); y++ ) {
				float f = p.getValue( 1f / b.getWidth() * x, 1f / b.getHeight() * y );
				RVec3 n = p.getDerivate( 1f / b.getWidth() * x, 1f / b.getHeight() * y );
				
				int c = 0;
				if( f < waterheight ) {
					float wd = f * (1f/waterheight);
					c = ColorGradient.linear( wd, 0xff_000050, 0xff_0000ff, 0xff_0090ff );
					n = new RVec3( 0, 0, 1 );
				} else if( f < beachheight ) {
					float gh = (f - waterheight) * (1f / (beachheight-waterheight));
					c = ColorGradient.linear( gh, 0xff_ffff00, 0xff_00ff00 );
				} else if( f < snowheight ) {
					float gh = (f - beachheight) * (1f / (snowheight-beachheight));
					c = ColorGradient.linear( gh, 0xff_00ff00, 0xff_00a000 );
				} else {
					float sh = (f - snowheight) * (1f / (1-snowheight));
					c = ColorGradient.linear( sh, 0xff_00a000, 0xff_ffffff );
				}
				
				int a = 0xff202020;

				int d = ColorOperations.diffuseLight( 
						lightVector,
						n,
						0xffffffff,
						0xffffffff );

				int s = ColorOperations.specularLight(
						lightVector,
						n,
						eyevector,
						0xff909090,
						0xff909090,
						10 );

				b.setRGB( x, y, ColorOperations.lightColor( c, a, d, s ) );
					
			}
	}
	
	private void drawTopology( BufferedImage b, Perlin2D p, Noise2D c1, Noise2D c2 ) {
		for( int x = 0; x < b.getWidth(); x++ )
			for( int y = 0; y < b.getHeight(); y++ ) {
				float f = p.getValue( 1f / b.getWidth() * x, 1f / b.getHeight() * y );
				
//				if( f < waterheight )
//					b.setRGB( x, y, 0xff0000ff );
//				else {
					float cv1 = c1.getValue( 1f / b.getWidth() * x, 1f / b.getHeight() * y );
					float cv2 = c2.getValue( 1f / b.getWidth() * x, 1f / b.getHeight() * y );
					
					float s = cv1 + cv2;
					if( s >= 1 ) b.setRGB( x, y, 0xffff0000 );
					if( s < 1 ) b.setRGB( x, y, 0xffffff00 );
					
//					if( cv1 > .5f && cv2 > .5f )	b.setRGB( x, y, 0xffffff00 );
//					if( cv1 > .5f && cv2 < .5f )	b.setRGB( x, y, 0xffff0000 );
//					if( cv1 < .5f && cv2 > .5f )	b.setRGB( x, y, 0xff00ff00 );
//					if( cv1 < .5f && cv2 > .5f )	b.setRGB( x, y, 0xff000000 );
//				}
					
			}
	}
	
	
}
